package com.zou.practice.rpc;

import lombok.Data;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Rpc服务端
 *
 * @author zou
 */
@Data
public class RpcServer {
    private int threadSize = 10;
    private ExecutorService threadPool;
    private Map<String, Object> servicePool;
    private int port = 4321;

    public RpcServer() {
        super();
        synchronized (this) {
            threadPool = Executors.newFixedThreadPool(this.threadSize);
        }
    }

    public RpcServer(int threadSize, int port) {
        this.threadSize = threadSize;
        this.port = port;
        synchronized (this) {
            threadPool = Executors.newFixedThreadPool(this.threadSize);
        }
    }

    public RpcServer(Map<String, Object> servicePool, int threadSize, int port) {
        this.threadSize = threadSize;
        this.servicePool = servicePool;
        this.port = port;
        synchronized (this) {
            threadPool = Executors.newFixedThreadPool(this.threadSize);
        }
    }

    public void service() throws IOException {
        ServerSocket serverSocket = new ServerSocket(port);
        while (true) {
            Socket receiveSocket = serverSocket.accept();
            final Socket socket = receiveSocket;
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        process(socket);
                        socket.close();
                    } catch (Exception e) {
                        //篇幅关系，省略对 ClassNotFoundException、NoSuchMethodException 等异常的处理

                    }

                }
            });
        }
    }

    private void process(Socket receiveSocket) throws IOException,
            ClassNotFoundException, NoSuchMethodException, SecurityException,
            IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, InstantiationException {

        ObjectInputStream objectinputStream = new ObjectInputStream(
                receiveSocket.getInputStream());
        TransportMessage message = (TransportMessage) objectinputStream
                .readObject();

        // 调用服务
        Object result = call(message);

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(receiveSocket.getOutputStream());
        objectOutputStream.writeObject(result);
        objectOutputStream.close();
    }

    private Object call(TransportMessage message) throws ClassNotFoundException,
            NoSuchMethodException, SecurityException, IllegalAccessException,
            IllegalArgumentException, InvocationTargetException,
            InstantiationException {
        if (servicePool == null) {
            synchronized (this) {
                servicePool = new HashMap<String, Object>();
            }
        }
        String interfaceName = message.getInterfaceName();
        Object service = servicePool.get(interfaceName);
        Class<?> serviceClass = Class.forName(interfaceName);

        // 检查 servicePool 中对象,若没有则生产对象
        if (service == null) {
            synchronized (this) {
                service = serviceClass.newInstance();
                servicePool.put(interfaceName, service);
            }
        }
        Method method = serviceClass.getMethod(message.getMethodName(),
                message.getParamsTypes());
        Object result = method.invoke(service, message.getParameters());
        return result;
    }

}